package com.plumelog.server.monitor;

import com.alibaba.fastjson.JSON;
import com.plumelog.core.client.AbstractClient;
import com.plumelog.core.constant.LogMessageConstant;
import com.plumelog.core.dto.WarningRule;
import com.plumelog.server.InitConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * className：PlumeLogMonitorRuleConfig
 * description： TODO
 * time：2020-07-02.15:48
 *
 * @author Tank
 * @version 1.0.0
 */
@Component
public class PlumeLogMonitorRuleConfig {
    private static final Logger logger = LoggerFactory.getLogger(PlumeLogMonitorListener.class);
    private static ConcurrentHashMap<String, List<WarningRule>> configMap = new ConcurrentHashMap<>();
    private static ConcurrentHashMap<String, List<WarningRule>> backConfigMap = new ConcurrentHashMap<>();
    @Autowired(required = false)
    private AbstractClient redisClient;
    @Autowired
    PlumeLogMonitorListener plumeLogMonitorListener;

    private static void parserConfig(String config) {
        WarningRule warningRule = JSON.parseObject(config, WarningRule.class);
        if (warningRule.getStatus() == 0) {
            return;
        }
        String key = getKey(warningRule.getAppName(), warningRule.getEnv());
        if (backConfigMap.containsKey(key)) {
            List<WarningRule> warningRules = backConfigMap.get(key);
            warningRules.add(warningRule);
            backConfigMap.put(key, warningRules);
        } else {
            List<WarningRule> lists = new ArrayList<>();
            lists.add(warningRule);
            backConfigMap.put(key, lists);
        }
    }

    private static String getKey(String appName, String env) {
        return appName + ":" + env;
    }

    /**
     * @param appName
     * @return
     */
    public List<WarningRule> getMonitorRuleConfig(String appName, String env) {
        if (configMap.isEmpty()) {
            initMonitorRuleConfig();
        }
        return configMap.get(getKey(appName, env));
    }

    public synchronized void initMonitorRuleConfig() {
        Map<String, String> configs = redisClient.hgetAll(LogMessageConstant.WARN_RULE_KEY);
        Collection<String> values = configs.values();
        Iterator<String> iterator = values.iterator();
        backConfigMap.clear();
        while (iterator.hasNext()) {
            parserConfig(iterator.next());
        }
        configMap = backConfigMap;
    }

    @Scheduled(cron = "*/30 * * * * ?")
    private void configureTasks() {
        if (!InitConfig.START_MODEL.equals(InitConfig.LITE_MODE_NAME)) {
            try {
                initMonitorRuleConfig();
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("更新规则配置失败 {}", e);

            }
        }
    }

    /**
     * 组装key
     *
     * @param appName   应用名
     * @param className 类名
     * @return
     */
    private static String getKey(String appName, String env, String className) {
        String key = LogMessageConstant.PLUMELOG_MONITOR_KEY + appName;
        if (!StringUtils.isEmpty(env)) {
            key = key + ":" + env;
        }
        if (!StringUtils.isEmpty(className)) {
            key = key + ":" + className;
        }
        return key;
    }
    @Scheduled(cron = "*/1 * * * * ?")
    public void alarm() {
        Collection<List<WarningRule>> values = backConfigMap.values();
        for (List<WarningRule> rules : values) {
            for (WarningRule warningRule : rules) {
              String key = getKey(warningRule.getAppName(), warningRule.getEnv(), warningRule.getClassName());
              try {
                  if (!redisClient.existsKey(key)) {
                      continue;
                  }
                  Long hsetnx = redisClient.hsetnx(key,"isAlarming", "true");
                  if (hsetnx != 1) {
                      continue;
                  }
                  String startTime = redisClient.hget(key, "startTime");
                  String endTime = redisClient.hget(key, "endTime");
                  if (endTime == null) {
                      //异常情况,直接抛弃数据
                      redisClient.del(key);
                      continue;
                  }
                  if (Long.valueOf(endTime) < System.currentTimeMillis()) {
                    //说明该判断告警了
                      String errorIncrString = redisClient.hget(key, "errorIncr");
                      Integer errorIncr = Integer.valueOf(errorIncrString);
                      if (errorIncr >= warningRule.getErrorCount()) {
                          //超过阈值,该报警了
                          String errorContent = redisClient.hget(key, "errorContent");
                          plumeLogMonitorListener.earlyWarning(warningRule, errorIncr, key, errorContent, warningRule.getClassName(), Long.valueOf(startTime), Long.valueOf(endTime));
                      } else {
                          redisClient.del(key);
                      }
                  }
              }finally {
                   redisClient.hdel(key,"isAlarming");
              }
            }
        }

    }
}
